"""
优化的NumPy比对器 - 在Cython不可用时提供较好的性能
"""

import numpy as np
from typing import List, Dict, Tuple, Optional
import logging
from concurrent.futures import ThreadPoolExecutor, as_completed
import multiprocessing

class OptimizedNumpyComparer:
    """使用NumPy优化的比对器"""
    
    def __init__(self, max_diff_reports: int = 100, use_parallel: bool = True):
        self.max_diff_reports = max_diff_reports
        self.use_parallel = use_parallel
        self.logger = logging.getLogger('numpy_comparer')
        self.num_workers = multiprocessing.cpu_count() if use_parallel else 1
        
    def extract_vc_info_vectorized(self, frames: List[Dict], frame_format: str) -> Tuple[List[int], List[int]]:
        """向量化提取虚拟信道信息"""
        if not frames:
            return [], []
            
        # 预分配数组
        n = len(frames)
        vc_ids = np.zeros(n, dtype=np.int32)
        frame_counts = np.zeros(n, dtype=np.int32)
        
        # 批量处理
        batch_size = 1000
        for i in range(0, n, batch_size):
            batch_end = min(i + batch_size, n)
            batch_frames = frames[i:batch_end]
            
            # 向量化处理批次
            for j, frame in enumerate(batch_frames):
                vc_ids[i+j] = int(frame.get('virtual_channel', 0))
                # 快速提取帧计数
                if 'payload' in frame and len(frame['payload']) >= 6:
                    payload = frame['payload']
                    if isinstance(payload, bytes):
                        frame_counts[i+j] = int.from_bytes(payload[3:5], 'big')
                    else:
                        frame_counts[i+j] = (payload[3] << 8) | payload[4]
                        
        return vc_ids.tolist(), frame_counts.tolist()
    
    def filter_frames_by_count_range(self, frames: List[Dict], vc_counts: List[int], 
                                   start_count: Optional[int], end_count: Optional[int]) -> List[Dict]:
        """使用NumPy高效过滤帧"""
        if not frames or (start_count is None and end_count is None):
            return frames
            
        # 转换为NumPy数组
        counts_arr = np.array(vc_counts, dtype=np.int32)
        
        # 创建掩码
        mask = np.ones(len(frames), dtype=bool)
        if start_count is not None:
            mask &= (counts_arr >= start_count)
        if end_count is not None:
            mask &= (counts_arr <= end_count)
            
        # 使用掩码过滤
        indices = np.where(mask)[0]
        return [frames[i] for i in indices]
    
    def batch_compare_optimized(self, frames1: List[Dict], frames2: List[Dict], 
                               compare_range: Optional[Tuple[int, int]] = None) -> Dict:
        """优化的批量比对"""
        if len(frames1) != len(frames2):
            return {
                'matching_count': 0,
                'mismatch_count': 0,
                'error_count': 0,
                'total_frames': len(frames1),
                'errors': ['帧数量不匹配']
            }
        
        n = len(frames1)
        results = {
            'matching_count': 0,
            'mismatch_count': 0,
            'error_count': 0,
            'total_frames': n,
            'mismatches': [],
            'errors': []
        }
        
        if n == 0:
            return results
            
        # 分批处理以减少内存占用
        batch_size = 10000
        
        if self.use_parallel and n > batch_size:
            # 并行处理大数据集
            with ThreadPoolExecutor(max_workers=self.num_workers) as executor:
                futures = []
                
                for i in range(0, n, batch_size):
                    batch_end = min(i + batch_size, n)
                    future = executor.submit(
                        self._compare_batch,
                        frames1[i:batch_end],
                        frames2[i:batch_end],
                        i,
                        compare_range
                    )
                    futures.append(future)
                
                # 收集结果
                for future in as_completed(futures):
                    batch_result = future.result()
                    results['matching_count'] += batch_result['matching_count']
                    results['mismatch_count'] += batch_result['mismatch_count']
                    results['error_count'] += batch_result['error_count']
                    results['mismatches'].extend(batch_result['mismatches'])
                    results['errors'].extend(batch_result['errors'])
        else:
            # 串行处理
            batch_result = self._compare_batch(frames1, frames2, 0, compare_range)
            results.update(batch_result)
            
        return results
    
    def _compare_batch(self, batch1: List[Dict], batch2: List[Dict], 
                      offset: int, compare_range: Optional[Tuple[int, int]]) -> Dict:
        """比对一个批次的帧"""
        batch_size = len(batch1)
        result = {
            'matching_count': 0,
            'mismatch_count': 0,
            'error_count': 0,
            'mismatches': [],
            'errors': []
        }
        
        # 预先提取所有payload并转换为NumPy数组
        payloads1 = []
        payloads2 = []
        valid_indices = []
        
        for i in range(batch_size):
            try:
                p1 = batch1[i]['payload']
                p2 = batch2[i]['payload']
                
                # 转换为NumPy数组
                if isinstance(p1, bytes):
                    arr1 = np.frombuffer(p1, dtype=np.uint8)
                else:
                    arr1 = np.asarray(p1, dtype=np.uint8)
                    
                if isinstance(p2, bytes):
                    arr2 = np.frombuffer(p2, dtype=np.uint8)
                else:
                    arr2 = np.asarray(p2, dtype=np.uint8)
                
                # 应用比对范围
                if compare_range:
                    start, end = compare_range
                    arr1 = arr1[start:end+1]
                    arr2 = arr2[start:end+1]
                
                payloads1.append(arr1)
                payloads2.append(arr2)
                valid_indices.append(i)
                
            except Exception as e:
                result['error_count'] += 1
                result['errors'].append(f"帧{offset + i}: {str(e)}")
        
        # 批量比对
        for idx, i in enumerate(valid_indices):
            if len(payloads1[idx]) != len(payloads2[idx]):
                result['mismatch_count'] += 1
                result['mismatches'].append({
                    'frame_index': offset + i,
                    'type': 'length_mismatch',
                    'length1': len(payloads1[idx]),
                    'length2': len(payloads2[idx])
                })
            elif np.array_equal(payloads1[idx], payloads2[idx]):
                result['matching_count'] += 1
            else:
                # 找出差异位置
                diff_mask = payloads1[idx] != payloads2[idx]
                diff_positions = np.where(diff_mask)[0]
                
                result['mismatch_count'] += 1
                
                # 只报告前几个差异
                reported_diffs = []
                for pos in diff_positions[:self.max_diff_reports]:
                    reported_diffs.append({
                        'position': int(pos),
                        'value1': int(payloads1[idx][pos]),
                        'value2': int(payloads2[idx][pos])
                    })
                
                result['mismatches'].append({
                    'frame_index': offset + i,
                    'type': 'content_mismatch',
                    'total_differences': len(diff_positions),
                    'differences': reported_diffs
                })
        
        return result
    
    def compare_frames_fast(self, frame1: Dict, frame2: Dict, 
                           compare_range: Optional[Tuple[int, int]] = None) -> Dict:
        """快速比对两个帧"""
        try:
            p1 = frame1['payload']
            p2 = frame2['payload']
            
            # 转换为NumPy数组
            if isinstance(p1, bytes):
                arr1 = np.frombuffer(p1, dtype=np.uint8)
            else:
                arr1 = np.asarray(p1, dtype=np.uint8)
                
            if isinstance(p2, bytes):
                arr2 = np.frombuffer(p2, dtype=np.uint8)
            else:
                arr2 = np.asarray(p2, dtype=np.uint8)
            
            # 应用比对范围
            if compare_range:
                start, end = compare_range
                arr1 = arr1[start:end+1]
                arr2 = arr2[start:end+1]
            
            # 长度检查
            if len(arr1) != len(arr2):
                return {
                    'type': 'length_mismatch',
                    'length1': len(arr1),
                    'length2': len(arr2)
                }
            
            # 快速相等检查
            if np.array_equal(arr1, arr2):
                return {'type': 'matching'}
            
            # 查找差异
            diff_mask = arr1 != arr2
            diff_positions = np.where(diff_mask)[0]
            
            differences = []
            for pos in diff_positions[:self.max_diff_reports]:
                differences.append({
                    'byte_position': int(pos),
                    'value1': int(arr1[pos]),
                    'value2': int(arr2[pos]),
                    'diff_bits': bin(int(arr1[pos]) ^ int(arr2[pos]))[2:].zfill(8)
                })
            
            result = {
                'type': 'content_mismatch',
                'total_differences': len(diff_positions),
                'reported_differences': len(differences),
                'differences': differences
            }
            
            if len(diff_positions) > self.max_diff_reports:
                result['truncated'] = True
                result['max_reports'] = self.max_diff_reports
            
            return result
            
        except Exception as e:
            return {
                'type': 'error',
                'message': str(e)
            } 